package com.ideaaedi.extspringcache.test.test4SerializerDeserializer;


import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import com.ideaaedi.extspringcache.annotation.ExtCacheable;
import com.ideaaedi.extspringcache.annotation.Redis;
import com.ideaaedi.extspringcache.custom.ExtRedisSerializerCustomizer;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 指定序列化器
 *
 * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
 * @since 2023-05-31 10:18:50
 */
@RestController
@RequestMapping("/se-de")
@SuppressWarnings("SpringCacheNamesInspection")
public class PointSerializerController {
    
    /**
     * 会因为序列化配置没生效导致报错(没生效，就会走默认的序列化器，而默认的序列化其要求被序列化对象需要实现Serializer接口才行)
     * <br />
     * 下面的序列化配置{@link SerializerConfig}只针对@ExtCacheable的，而不是针对@Cacheable注解的的
     */
    @GetMapping("/one")
    @Cacheable(cacheNames = "se-de", key = "'one' + #param1")
    public Object one(String param1) {
        UserInfo user = UserInfo.builder()
                .key1("张三" + RandomStringUtils.random(5, true, true))
                .key2(ThreadLocalRandom.current().nextLong())
                .key3(ThreadLocalRandom.current().nextInt())
                .key4(ThreadLocalRandom.current().nextBoolean())
                .key5(LocalDateTime.now())
                .key6(Lists.newArrayList(
                        RandomStringUtils.random(1, true, true),
                        RandomStringUtils.random(2, true, true),
                        RandomStringUtils.random(3, true, true)
                ))
                .build();
        System.err.println("进PointSerializerController#one了." + user);
        return user;
    }
    
    @GetMapping("/two")
    @ExtCacheable(cacheNames = "se-de", key = "'two' + #param1",
            redis = @Redis(useRedisTemplate = "redisTemplate", expireTime = 60))
    public UserInfo two(String param1) {
        UserInfo user = UserInfo.builder()
                .key1("张三" + RandomStringUtils.random(5, true, true))
                .key2(ThreadLocalRandom.current().nextLong())
                .key3(ThreadLocalRandom.current().nextInt())
                .key4(ThreadLocalRandom.current().nextBoolean())
                .key5(LocalDateTime.now())
                .key6(Lists.newArrayList(
                        RandomStringUtils.random(1, true, true),
                        RandomStringUtils.random(2, true, true),
                        RandomStringUtils.random(3, true, true)
                ))
                .build();
        System.err.println("进PointSerializerController#two了." + user);
        return user;
    }
    
    @Component
    public static class SerializerConfig implements ExtRedisSerializerCustomizer {
    
        @NonNull
        @Override
        public RedisSerializationContext.SerializationPair<String> keySerializer() {
            return RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer(StandardCharsets.UTF_8));
        }
    
        @NonNull
        @Override
        public RedisSerializationContext.SerializationPair<Object> valueSerializer() {
            ObjectMapper om = new ObjectMapper().findAndRegisterModules();
            om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            om.activateDefaultTyping(om.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
            Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(om, Object.class);
            return RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer);
        }
    }
    
    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public static class UserInfo {
     private String key1;
     private Long key2;
     private Integer key3;
     private Boolean key4;
     private LocalDateTime key5;
     private List<String> key6;
    }
}
